#include <iostream>
#include <functional>

using std::cout;
using std::endl;
using std::function;
using std::string;

//全局变量
int global = 100;

void test0()
{
    auto f1 = [](){
        cout << "lambda test" << endl;
        //对于全局变量，不受捕获列表的影响
        //想用就用
        cout << "global:" << global << endl;
    };
    f1();

    auto f2 = []{
        cout << "lambda test2" << endl;
    };
    f2();

    function<void()> f3 = [](){
        cout << "lambda test3" << endl;
    };
    f3();
}

void test1()
{
    int a = 1, b = 2;
    string s1("hello");
    //捕获的变量必须要在lambda表达式之前
    auto f1 = [a, b, s1](){
        cout << "a:" << a << endl;
        cout << "b:" << b << endl;
        cout << "s1:" << s1 << endl;
    };
    f1();

    //以值传递的方式， 捕获外部的所有变量
    auto f2 = [=]{
        cout << "\n";
        cout << "a:" << a << endl;
        cout << "b:" << b << endl;
        cout << "s1:" << s1 << endl;
    };
    f2();

    //当希望修改捕获的变量时，需要加上mutable关键字
    auto f3 = [=]() mutable {
        cout << "\n";
        ++a;
        cout << "a:" << a << endl;// a = 2
    };
    f3();
    cout << "test1中的a:" << a << endl;//1
}

void test2()
{
    int a = 1, b = 2;
    string s1("hello");
    //捕获的变量必须要在lambda表达式之前
#if 0
    //以引用的方式捕获某一个变量
    auto f1 = [&a, &b, &s1](){
        ++a;
        ++b;
        s1.append("world");
        cout << "a:" << a << endl;
        cout << "b:" << b << endl;
        cout << "s1:" << s1 << endl;
    };
    f1();
#endif

    //以引用传递的方式， 捕获外部的所有变量
    auto f2 = [&]{
        cout << "\n 以引用方式捕获所有变量" << endl;
        ++a;
        ++b;
        s1.append("world");
        cout << "a:" << a << endl;
        cout << "b:" << b << endl;
        cout << "s1:" << s1 << endl;
    };
    f2();

    cout << "test1中的a:" << a << endl;//1
    cout << "test1中的b:" << b << endl;//1
    cout << "test1中的s1:" << s1 << endl;//1
}

void test3()
{
    int a = 1, b = 2;
    string s1("hello");

    //除了变量a以引用方式进行捕获，其他的都是值传递方式进行捕获
    auto f1 = [=, &a, &b]() mutable {
        ++a;// 可以直接修改
        ++b;//值传递方式，不可以直接修改
        s1.append("world");
        cout << "a:" << a << endl;
        cout << "b:" << b << endl;
        cout << "s1:" << s1 << endl;
    };
    f1();
    cout << "\ntest3中的a:" << a << endl;
    cout << "test3中的b:" << b << endl;//
    cout << "test3中的s1:" << s1 << endl;//
                                         
#if 0
    //捕获列表中的 = 必须要放在最前面，否则报错
    auto f2 = [&a,&b,=]() {
        cout << "a:" << a << endl;
    };
    f2();
#endif
}


void test4()
{
    cout << "test4() " << endl;
    int a = 1, b = 2;
    string s1("hello");
    //除了a以值传递方式进行捕获，其他的变量都以引用方式进行捕获
    auto f1 = [&, a, b]() mutable{
        ++a;//a是被复制的一份，不会影响外部的a
        cout << "a:" << a << endl;
        b++;
        s1.append("world");
        cout << "b:" << b << endl;
        cout << "s1:" << s1 << endl;
    };
    f1();

    cout << "\ntest4中的a:" << a << endl;//1
    cout << "test4中的b:" << b << endl;//1
    cout << "test4中的s1:" << s1 << endl;//1
}

class Foo
{
public:
    void print(){
        cout << "_data:" << _data << endl;
        //在成员函数中定义的lambda表达式无法直接获取
        //非静态的数据成员, 但可以直接获取静态数据成员
        auto f1 = [](){
            //cout << "_data:" << _data << endl;//error
            cout << "_sdata2:" << _sdata2 << endl;//ok
        };
        //f1();

        //在成员函数中，捕获了this指针就可以直接操作
        //非静态数据成员了
        auto f2 = [this](){
            cout << "捕获this指针之后_data:" << this->_data << endl;
            this->show();
        };
        f2();
    }

    void show() const
    {   cout << "show()" << endl;   }

private:
    int _data = 10;
    static int _sdata2;
};

int Foo::_sdata2 = 100;

void test5()
{
    Foo foo;
    foo.print();
}

int main()
{
    /* test0(); */
    /* test1(); */
    /* test2(); */
    /* test3(); */
    /* test4(); */
    test5();

    return 0;
}

